package edu.chalmers.targine;

import java.util.Iterator;
import java.util.Vector;

import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLUtils;
import android.util.Log;
import edu.dhbw.andar.util.Group;
import edu.dhbw.andar.util.Material;
import edu.dhbw.andar.util.Model;

public abstract class Mesh {
	protected Model model;
	protected String type;
	
	public abstract Model getModel();
	
	public abstract void update();
	
	@Override
	public abstract void finalize();
	
	public abstract boolean isFinalized();
	
	public abstract boolean hasModel();
	
	public boolean hasType(String type){
		return this.type != null && this.type.equals(type);
	}
	
	public void init(GL10 gl){
		// separate texture from non textured groups for performance reasons
		Vector<Group> groups = model.getGroups();
		Vector<Group> texturedGroups = new Vector<Group>();
		Vector<Group> nonTexturedGroups = new Vector<Group>();
		
		for (Iterator<Group> iterator = groups.iterator(); iterator.hasNext();){
			Group currGroup = iterator.next();
			if (currGroup.isTextured()){
				texturedGroups.add(currGroup);
			} else{
				nonTexturedGroups.add(currGroup);
			}
		}
		model.texturedGroups = texturedGroups.toArray(new Group[texturedGroups.size()]);
		model.nonTexturedGroups = nonTexturedGroups.toArray(new Group[nonTexturedGroups.size()]);
		
		int[]  tmpTextureID = new int[1];
		//load textures of every material(that has a texture):
		Log.d("Arbject", "Materials: " + model.getMaterials().size());
		Iterator<Material> materialI = model.getMaterials().values().iterator();
		
		while(materialI.hasNext()){
			Log.d("Arbject", "Has next...");
			Material material = materialI.next();
			if(material.hasTexture()){
				//load texture
				gl.glGenTextures(1, tmpTextureID, 0);
				gl.glBindTexture(GL10.GL_TEXTURE_2D, tmpTextureID[0]);
				
				Log.d("Arbject", "Loading texture: " + tmpTextureID[0]);
				model.textureIDs.put(material, tmpTextureID[0]);
				
				GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, material.getTexture(),0);
				material.getTexture().recycle();
				gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
				gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
			}
		}
	}
	
	public void draw(GL10 gl){
		gl.glPushMatrix();
		//do positioning:
		gl.glTranslatef(model.xpos, model.ypos, model.zpos);
		gl.glScalef(model.xscale, model.yscale, model.zscale);
		gl.glRotatef(model.xrot, 1, 0, 0);
		gl.glRotatef(model.yrot, 0, 1, 0);
		gl.glRotatef(model.zrot, 0, 0, 1);
		
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
		
		//first draw non textured groups
		gl.glDisable(GL10.GL_TEXTURE_2D);
		int cnt = model.nonTexturedGroups.length;
		for (int i = 0; i < cnt; i++) {
			Group group = model.nonTexturedGroups[i];
			Material mat = group.getMaterial();
			if(mat != null) {
				gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, mat.specularlight);
				gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, mat.ambientlight);
				gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, mat.diffuselight);
				gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, mat.shininess);
			}
			gl.glVertexPointer(3,GL10.GL_FLOAT, 0, group.vertices);
	        gl.glNormalPointer(GL10.GL_FLOAT,0, group.normals);
	        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, group.vertexCount);
		}
		
		//now we can continue with textured ones
		gl.glEnable(GL10.GL_TEXTURE_2D);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		
		cnt = model.texturedGroups.length;
		for (int i = 0; i < cnt; i++) {
			Group group = model.texturedGroups[i];
			Material mat = group.getMaterial();
			if(mat != null) {
				gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, mat.specularlight);
				gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, mat.ambientlight);
				gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, mat.diffuselight);
				gl.glMaterialf(GL10.GL_FRONT_AND_BACK, GL10.GL_SHININESS, mat.shininess);
				if(mat.hasTexture()) {
					gl.glTexCoordPointer(2,GL10.GL_FLOAT, 0, group.texcoords);
					gl.glBindTexture(GL10.GL_TEXTURE_2D, model.textureIDs.get(mat).intValue());
				}
			}
			gl.glVertexPointer(3,GL10.GL_FLOAT, 0, group.vertices);
	        gl.glNormalPointer(GL10.GL_FLOAT,0, group.normals);
	        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, group.vertexCount);
		}
		
		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
		gl.glPopMatrix();
	}
}
